﻿#region 命名空间
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.IO;
using System.Xml.Serialization;
using DW.SharpTools;
using MonoGameContentProcessors;
#endregion

namespace ContentFactory
{
    /// <summary>
    /// 表示 ContentFactory 的项目文档。
    /// </summary>
    [XmlInclude(typeof(ContentDirectory))]
    [XmlInclude(typeof(ContentBuilder))]
    public sealed class Project : ViewObject
    {
        #region 字段

        Dictionary<MonoGamePlatform, Configuration> _configCache;

        #endregion

        #region 事件

        /// <summary>
        /// 当素材添加到项目后触发。
        /// </summary>
        public event Action<ContentBuilder> ContentAdded;
        internal void OnContentAdded(ContentBuilder content)
        {
            if (ContentAdded != null)
                ContentAdded(content);
        }

        /// <summary>
        /// 当素材从项目删除后触发。
        /// </summary>
        public event Action<ContentBuilder> ContentRemoved;
        internal void OnContentRemoved(ContentBuilder content)
        {
            if (ContentRemoved != null)
                ContentRemoved(content);
        }

        /// <summary>
        /// 当目录添加到项目后触发。
        /// </summary>
        public event Action<ContentDirectory> DirectoryAdded;
        internal void OnDirectoryAdded(ContentDirectory directory)
        {
            if (DirectoryAdded != null)
                DirectoryAdded(directory);
        }

        /// <summary>
        /// 当目录从项目删除后触发。
        /// </summary>
        public event Action<ContentDirectory> DirectoryRemoved;
        internal void OnDirectoryRemoved(ContentDirectory directory)
        {
            if (DirectoryRemoved != null)
                DirectoryRemoved(directory);
        }

        #endregion

        #region 属性

        /// <summary>
        /// 项目的保存路径。
        /// </summary>
        [XmlIgnore]
        public string SavePath
        {
            get { return _savePath; }
            internal set { _savePath = value; }
        }
        string _savePath;

        /// <summary>
        /// 指示项目是否已经编辑过（需要保存）。
        /// </summary>
        [XmlIgnore]
        public bool Dirty
        {
            get { return _dirty; }
            internal set { _dirty = value; }
        }
        bool _dirty;

        /// <summary>
        /// 是否默认压缩素材。
        /// </summary>
        public bool DefaultCompressContent
        {
            get { return _defaultCompressContent; }
            set
            {
                if (_defaultCompressContent != value)
                {
                    _defaultCompressContent = value;
                    this.Raise("DefaultCompressContent");
                }
            }
        }
        bool _defaultCompressContent;

        /// <summary>
        /// 各平台对应的游戏目录。
        /// </summary>
        public ObservableCollection<Configuration> Configurations
        {
            get { return _configurations; }
            set { _configurations = value; }
        }
        ObservableCollection<Configuration> _configurations;
        
        /// <summary>
        /// 素材根目录集合。
        /// </summary>
        public EnhancedObservableCollection<ContentDirectory> RootDirectories
        {
            get { return _rootDirectories; }
            set { _rootDirectories = value; }
        }
        EnhancedObservableCollection<ContentDirectory> _rootDirectories;
        
        #endregion

        #region 初始化

        /// <summary>
        /// 初始化。
        /// </summary>
        private Project()
        {
        }

        #endregion

        #region 方法

        /// <summary>
        /// 保存项目。
        /// </summary>
        public void Save(string fileName)
        {
            using (Stream stream = new FileStream(fileName, FileMode.Create))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Project), PipelineManager.PipelineTypes);
                serializer.Serialize(stream, this);
            }
            _dirty = false;
        }

        /// <summary>
        /// 创建项目。
        /// </summary>
        public static Project Create()
        {
            Project project = new Project();
            project._dirty = true;
            project._configurations = new ObservableCollection<Configuration>()
            {
                new Configuration() { GamePlatform = MonoGamePlatform.Windows},
                new Configuration() { GamePlatform = MonoGamePlatform.Windows8 },
                new Configuration() { GamePlatform = MonoGamePlatform.iOS },
                new Configuration() { GamePlatform = MonoGamePlatform.Android },
                new Configuration() { GamePlatform = MonoGamePlatform.Linux },
                new Configuration() { GamePlatform = MonoGamePlatform.OSX },
                new Configuration() { GamePlatform = MonoGamePlatform.PSM },
            };
            project._rootDirectories = new EnhancedObservableCollection<ContentDirectory>();
            project._rootDirectories.CollectionChanged += project.RootDirectories_CollectionChanged;
            project.CacheConfigurations();
            return project;
        }

        /// <summary>
        /// 加载项目。
        /// </summary>
        public static Project Load(string fileName)
        {
            Project project = null;
            using (Stream stream = new FileStream(fileName, FileMode.Open))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(Project), PipelineManager.PipelineTypes);
                project = serializer.Deserialize(stream) as Project;
            }
            if (project != null)
            {
                foreach (var root in project._rootDirectories)
                {
                    root.Project = project;
                    Init(root, project);
                }
                project._rootDirectories.CollectionChanged += project.RootDirectories_CollectionChanged;
                project.CacheConfigurations();
                return project;
            }
            return null;
        }

        // 初始化项目。
        static void Init(ContentDirectory directory, Project project)
        {
            foreach (var child in directory.Children)
            {
                child.Project = directory.Project;
                child.Parent = directory;
                if (child is ContentBuilder)
                {
                    ContentBuilder content = child as ContentBuilder;
                    content.SetAttributes(PipelineManager.GetImporterAttribute(content.Importer),
                        PipelineManager.GetProcessorAttribute(content.Processor));
                }
                else
                    Init(child as ContentDirectory, project);
            }
        }

        // 初始化配置。
        void CacheConfigurations()
        {
            _configCache = new Dictionary<MonoGamePlatform, Configuration>();
            foreach (var config in _configurations)
            {
                _configCache.Add(config.GamePlatform, config);
            }
        }

        /// <summary>
        /// 获取指定平台的配置。
        /// </summary>
        internal Configuration GetConfig(MonoGamePlatform gamePlatform)
        {
            if (gamePlatform == MonoGamePlatform.None)
                return null;
            else
                return _configCache[gamePlatform];
        }

        #endregion

        #region 事件处理

        void RootDirectories_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    this.OnDirectoryAdded(e.NewItems[0] as ContentDirectory);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    this.OnDirectoryRemoved(e.OldItems[0] as ContentDirectory);
                    break;
                default:
                    break;
            }
        }

        #endregion
    }
}
